<template>
  <view class="blog-component-plate-chart" @click="this.$emit('onClickListener')" :style="[shellStyle,sideLineStyle]">
    <view class="blog-component-plate-chart-border" :style="mainStyle">
      <view class="blog-component-plate-chart-line" v-for="index in number" :style="getStyle(index)"/>
      <view class="blog-component-plate-chart-content" :style="[fontStyle,contentStyle]">
        <template v-if="progress&&!noTitle">
          <text> {{ `${progress * 100}%` }}</text>
        </template>
        <template v-else>
          <slot></slot>
        </template>
      </view>
      <view class="blog-component-plate-chart-fan-disk" :style="[kernelStyle,stripeStyle]"/>
      <view class="blog-component-plate-chart-chassis" :style="chassisStyle"/>
    </view>
  </view>
</template>

<script>
export default {
  props: {
    size: {
      type: Number,
      default: 80
    },
    degrees: {
      type: Number,
      default: 10
    },
    progress: {
      type: Number,
      default: 0,
      required: true,
    },
    fontSize: {
      type: Number,
      default: 14
    },
    splitLineSize: {
      type: Number,
      default: 2
    },
    transitionValue: {
      type: Number,
      default: 0.1
    },
    reverse: {
      type: Boolean,
      default: false
    },
    transitionMinValue: {
      type: Number,
      default: 0.05
    },
    distancePercentage: {
      type: Number,
      default: 0.2
    },
    noTitle: {
      type: Boolean,
      default: false
    },
    color: {
      type: String,
      default: "#00e8a0"
    },
    lowerColor: {
      type: String,
      default: "#cfcfcf"
    },
    backgroundColor: {
      type: String,
      default: "#fff"
    },
    sideLineColors: Array,
    stripeStyle: {
      type: String,
      default: String
    },
    sideLineStyle: {
      type: String,
      default: String
    },
    contentStyle: {
      type: Object,
      default: {}
    }
  },
  computed: {
    outSize() {
      return this.size * (1 + this.distancePercentage);
    },
    borderSize() {
      return this.size * this.distancePercentage;
    },
    number() {
      return 180 / this.degrees;
    },
    backgroundImage() {
      let lineColors = this.sideLineColors || this.sideDefaultColor;
      return `linear-gradient(to right, ${this.backgroundColor}, ${this.backgroundColor}),
          linear-gradient(180deg, ${function () {
        let colorStr = "";
        for (let i = 0; i < lineColors.length; i++) {
          let colors = lineColors[i];
          colorStr += `${colors.color} ${colors.progress * 100}%`;
          if (i !== lineColors.length - 1) {
            colorStr += ",";
          }
        }
        return colorStr;
      }()})`
    },
    sideDefaultColor() {
      return [
        {color: this.getOpacityColor(this.color, 0), progress: 0.05},
        {color: this.getOpacityColor(this.color, 0.1), progress: 0.1},
        {color: this.getOpacityColor(this.color, 0.2), progress: 0.2},
        {color: this.getOpacityColor(this.color, 0.3), progress: 0.3},
        {color: this.color, progress: 1},
      ]
    },
    progressHandler() {
      let colorStr = "";
      if (this.reverse) {
        if (this.progress === 0) {
          colorStr += `${this.color} 0,${this.lowerColor} 0,`;
          colorStr += `${this.lowerColor} 100%`;
        } else if (this.progress === 1) {
          colorStr += `${this.color} 0%,${this.color} 100%`;
        } else if (this.progress >= (1 - this.transitionMinValue)) {
          colorStr += `${this.color} ${this.progress * 100}%,${this.lowerColor} ${0.5 * 100}%,`;
          colorStr += `${this.lowerColor} 100%`;
        } else {
          colorStr += `${this.color} ${this.progress * 100}%,${this.lowerColor} ${this.progress * 100 + this.transitionValue * 100}%,`;
          colorStr += `${this.lowerColor} 100%`;
        }
      } else {
        if (this.progress === 0) {
          colorStr += `${this.color} 0,${this.lowerColor} 0,`;
          colorStr += `${this.lowerColor} 100%`;
        } else if (this.progress === 1) {
          colorStr += `${this.color} 0%,${this.color} 100%`;
        } else if (this.progress >= (1 - this.transitionMinValue)) {
          colorStr += `${this.color} ${this.progress * 100}%,${this.lowerColor} ${0.5 * 100}%,`;
          colorStr += `${this.lowerColor} 100%`;
        } else {
          colorStr += `${this.color} ${this.progress * 100}%,${this.lowerColor} ${this.progress * 100 + this.transitionValue * 100}%,`;
          colorStr += `${this.lowerColor} 100%`;
        }
      }
      return colorStr;
    },
    shellStyle() {
      return {
        width: `${this.outSize}px`,
        height: `${this.outSize}px`,
        backgroundImage: this.backgroundImage
      }
    },
    mainStyle() {
      return {
        width: `${this.size}px`,
        height: `${this.size}px`,
        border: `${this.borderSize}rpx solid transparent`
      }
    },
    kernelStyle() {
      return {
        width: `${this.size}px`,
        height: `${this.size}px`,
        background: `conic-gradient(${this.progressHandler})`,
        transform: `rotateY(${this.reverse ? 180 : 0}deg)`
      }
    },
    chassisStyle() {
      return {
        backgroundColor: this.backgroundColor,
        borderRadius: "100%",
        width: `${this.size - this.borderSize}px`,
        height: `${this.size - this.borderSize}px`,
      }
    },
    fontStyle() {
      return {
        fontSize: `${this.fontSize}px`,
        color: this.fontColor,
      }
    }
  },
  emits: ["onClickListener"],
  methods: {
    getStyle(index) {
      return {
        width: `${this.splitLineSize}px`,
        height: `${this.size * 2}px`,
        backgroundColor: this.backgroundColor,
        transform: `rotateZ(${index * this.degrees}deg)`
      }
    },
    getOpacityColor(thisColor, thisOpacity) {
      let theColor = thisColor.toLowerCase();
      let r = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
      if (theColor && r.test(theColor)) {
        if (theColor.length === 4) {
          let sColorNew = "#";
          for (let i = 1; i < 4; i += 1) {
            sColorNew += theColor.slice(i, i + 1).concat(theColor.slice(i, i + 1));
          }
          theColor = sColorNew;
        }
        let sColorChange = [];
        for (let i = 1; i < 7; i += 2) {
          sColorChange.push(parseInt("0x" + theColor.slice(i, i + 2)));
        }
        return "rgba(" + sColorChange.join(",") + "," + thisOpacity + ")";
      }
      return theColor;
    }
  }
}
</script>

<style>

.blog-component-plate-chart {
  position: relative;
  box-sizing: border-box;
  border-radius: 100%;
  display: flex;
  overflow: hidden;
  align-items: center;
  justify-content: center;
  border: 2px solid transparent;
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
}

.blog-component-plate-chart-border {
  position: relative;
  box-sizing: border-box;
  border-radius: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
}

.blog-component-plate-chart-fan-disk {
  position: absolute;
  z-index: 1;
  border-radius: 100%;
}

.blog-component-plate-chart-line {
  position: absolute;
  z-index: 2;
}

.blog-component-plate-chart-content {
  z-index: 5;
}

.blog-component-plate-chart-chassis {
  position: absolute;
  z-index: 4;
}

</style>
